#include "r_socket_obj_manager.h"

#include "utilities/r_logger.h"

namespace eniac
{

std::int32_t r_socket_obj_manager::m_last_socket_id {0};


r_socket_obj_manager* r_socket_obj_manager::get_instance()
{
    static r_socket_obj_manager instance;
    return & instance;
}

r_socket::ptr r_socket_obj_manager::create_socket_obj(r_socket_type type)
{
    if (r_socket_type::SOCKET_TYPE_UNKNOWN == type)
    {
        return r_socket::ptr{nullptr};
    }

    std::lock_guard<std::recursive_mutex> lg{m_socket_obj_mutex};
    ++m_last_socket_id;
    r_socket::ptr socket_obj = std::make_shared<r_socket>();
    if (nullptr != socket_obj.get())
    {
        socket_obj->m_socket_id = m_last_socket_id;
        socket_obj->m_socket_type = type;
        m_id_socket_map[socket_obj->m_socket_id] = socket_obj;
        m_old_fds[socket_obj->m_socket_id] = INVALID_SOCKET_FD;
    }

    return socket_obj;
}

r_socket::ptr r_socket_obj_manager::get_socket_obj_by_id(std::int32_t id)
{
    std::lock_guard<std::recursive_mutex> lg{m_socket_obj_mutex};

    auto it = m_id_socket_map.find(id);
    if (it == m_id_socket_map.end())
    {
        return r_socket::ptr{nullptr};
    }

    return it->second;
}

r_socket::ptr r_socket_obj_manager::get_socket_obj_by_fd(std::int32_t fd)
{
    std::lock_guard<std::recursive_mutex> lg{m_socket_obj_mutex};

    auto it = m_fd_socket_map.find(fd);
    if (it == m_fd_socket_map.end())
    {
        return r_socket::ptr{nullptr};
    }

    return it->second;
}

void r_socket_obj_manager::update_socket_obj(r_socket::ptr obj)
{
    std::lock_guard<std::recursive_mutex> lg{m_socket_obj_mutex};

    if (nullptr == obj.get())
    {
        return;
    }

    if (INVALID_SOCKET_ID == obj->m_socket_id)
    {
        return;
    }

    m_id_socket_map[obj->m_socket_id] = obj;

    std::int32_t old_fd = m_old_fds[obj->m_socket_id];
    if (old_fd != obj->m_socket_fd)
    {
        m_old_fds[obj->m_socket_id] = obj->m_socket_fd;
        if (INVALID_SOCKET_FD == old_fd)
        {
            m_fd_socket_map[obj->m_socket_fd] = obj;
        }
        if (INVALID_SOCKET_FD == obj->m_socket_fd)
        {
            m_fd_socket_map.erase(old_fd);
        }
    }
}

void r_socket_obj_manager::remove_socket_obj(std::int32_t id)
{
    std::lock_guard<std::recursive_mutex> lg{m_socket_obj_mutex};

    auto id_it = m_id_socket_map.find(id);
    if (id_it == m_id_socket_map.end())
    {
        return;
    }

    if (INVALID_SOCKET_FD != id_it->second->m_socket_fd)
    {
        m_fd_socket_map.erase(id_it->second->m_socket_fd);
    }

    m_id_socket_map.erase(id_it);
    m_old_fds.erase(id);
}

std::set<r_socket::fd_t> r_socket_obj_manager::get_all_socket_fds()
{
    std::lock_guard<std::recursive_mutex> lg{m_socket_obj_mutex};
    std::set<r_socket::fd_t> ret_fds;

    for (const auto& socket_obj_it : m_fd_socket_map)
    {
        ret_fds.insert(socket_obj_it.first);
    }

    return ret_fds;
}

std::int32_t r_socket_obj_manager::get_fd_num()
{
    std::lock_guard<std::recursive_mutex> lg{m_socket_obj_mutex};
    return m_fd_socket_map.size();
}

r_socket::ptr r_socket_obj_manager::is_partner_exists(r_socket::ptr self, r_socket::ptr in_partner)
{
    if (nullptr == self.get() || nullptr == in_partner.get())
    {
        return r_socket::ptr{};
    }

    if (true == self->m_parnters.empty())
    {
        return r_socket::ptr{};
    }

    for (r_socket::id_t partner_id : self->m_parnters)
    {
        r_socket::ptr partner_obj = r_socket_obj_manager::get_instance()->get_socket_obj_by_id(partner_id);
        if (nullptr == partner_obj.get())
        {
            continue;
        }

        LOG_DBG() << "orign partner address is " << partner_obj->m_own_address << " port is " << partner_obj->m_own_port;
        LOG_DBG() << "new patner address is " << in_partner->m_own_address << " port is " << in_partner->m_own_port;

        if (true == r_socket::are_addresses_equal(partner_obj, in_partner))
        {
            return partner_obj;
        }
    }

    return r_socket::ptr{}; 
}


}